//
// Created by wzr on 2021/5/8.
//

#ifndef UNTITLED1_SCHOOLCARD_H
#define UNTITLED1_SCHOOLCARD_H

#include <cstdio>
#include <string>
#include <iostream>
#include <ctime>
#include "ctrlcur.h"
#include "Bus.h"
#include "data.h"
#include <list>

enum TYPE{
    teacher=1, student=2, limit=3
};
class User {
private:
    int             id{};
    int             type{};
    std::string     name;
    std::string     position;
public:
    int getId() const;

    inline std::string getName() const {return name;}
    inline std::string getType() const;

    const string &getPosition() const;

    User() = default;
    User(int, int , std::string, std::string);
};

class Card {
protected:
    User*   cardholder;                 //Who own the card
    int     num;                        //Unique id of the card
    int     balance;                    //Balance of the card
    int     taking;                     //Having taken
    bool    state = true;               //true - valid
public:
    Card()=default;
    Card(User*, int, int, int, int);                         //Init

    inline int getNum() const {return num;}             //Get number/id of the card

    void ShowInfo() const;                              //Print the info of the card

    void AddMoney(int);                                 //Add money to the card

    /*
     * Take a bus with this card.(Using Template Method Design Pattern)
     * Pass the pointer of the bus taken
     * 1. Judge if the card is valid.
     * 2. Judge if the bus is full.
     * 3. ShowInfo()
     * 4. Taking++ (Update the database)
     * 5. 此时还没有真正乘车，乘车步骤在下一步
     * 6. ShowTakingResult()  (virtual function. 不同卡的逻辑实现不同)
     */
    void TakeBus(Bus* busTaken);


    /*
     * virtual function. Using Template Method.
     * Should be invoked in Takebus()
     * Pass the pointer of the bus taken.
     */
    virtual void ShowTakingResult(Bus* busTaken){};

    /*
     * Add one taking to the Cards. Taking++
     * Should update the info to the database and local variable
     * Invoke incTaking();
     */
    void addTaking();

    /*
     * Get the state of the card
     */
    inline std::string getState() const;

    /*
     * Set the state of the card
     * Update the state to both database and the object
     */
    inline void setState(bool stat){state = stat;}
};

class StudentCard: public Card {
public:
    /*
     * Show Result of the taking. Part of takeBus().
     * Should update balance in this function.
     */
    void ShowTakingResult(Bus* busTaken) override;

    StudentCard(User*, int, int, int, int);
};

class TeacherCard: public Card {
public:
    TeacherCard(User*, int, int, int, int);

    /*
     * Show Result of the taking. Part of takeBus().
     * Should update balance in this function.
     * Teacher take bus for free.
     */
    void ShowTakingResult(Bus* busTaken) override;
};

class LimitCard: public Card {
private:
    /*
     * The free times of LimitCard is 20 every month;
     * Cost 2 yuan after free is 0
     */
    int free;
public:

    void ShowTakingResult(Bus* busTaken) override;

    LimitCard(User*, int, int, int, int, int);
};

#endif //UNTITLED1_SCHOOLCARD_H
